﻿//========================================================= 
/**@file lmdb_extractor.h
 * @brief lmdb封装
 * 
 * @date 2018-06-05   15:40:11
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_LMDB_EXTRACTOR_H_
#define _LIBZHOUYB_LMDB_EXTRACTOR_H_
//--------------------------------------------------------- 
#include <lmdb.h>

#include "../../include/Base.h"

#include "../../extension/ability/FolderHelper.h"
using zhou_yb::extension::ability::FolderHelper;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace wrapper {
namespace lmdb_extractor {
//--------------------------------------------------------- 
/* 类引用声明 */
class lmdb_txn;
class lmdb_const_txn;

class lmdb_dbi;
class lmdb_const_dbi;

class lmdb_cursor;
class lmdb_const_cursor;
//--------------------------------------------------------- 
/// lmdb 基本对象封装
class lmdb_base
{
protected:
    int _err_code;
    string _err_msg;

    bool _log_err(int err)
    {
        _err_code = err;
        bool bOK = (err == MDB_SUCCESS);
        if(!bOK)
        {
            _err_msg = mdb_strerror(err);
        }
        else
        {
            _err_msg = "";
        }
        return bOK;
    }
    void _log_err(const char* err_msg)
    {
        _err_code = DeviceError::OperatorErr;
        _err_msg = err_msg;
    }
    inline void _log_err(const lmdb_base& obj)
    {
        _err_code = obj._err_code;
        _err_msg = obj._err_msg;
    }
public:
    lmdb_base() : _err_code(MDB_SUCCESS), _err_msg("") {}

    inline int error() const
    {
        return _err_code;
    }
    inline const string& error_msg() const
    {
        return _err_msg;
    }
};
//--------------------------------------------------------- 
/// lmdb MDB_env*的封装
class lmdb_env_base : public lmdb_base
{
protected:
    string _dir;
    uint _flags;
    mdb_mode_t _mode;
    shared_obj<MDB_env*> _env;
public:
    lmdb_env_base()
    {
        _dir = "";
        _flags = 0;
        _mode = 0;
        _env = NULL;
    }
    virtual ~lmdb_env_base()
    {
        dispose();
    }

    /// 获取打开env时的目录
    inline const string& get_dir() const
    {
        return _dir;
    }
    /// 获取打开时的flags
    inline uint get_flags()
    {
        mdb_env_get_flags(_env, &_flags);
        return _flags;
    }
    /// 获取打开时的mode
    inline mdb_mode_t get_mode() const
    {
        return _mode;
    }
    /// 操作符转换
    inline operator MDB_env*() const
    {
        return _env;
    }
    /// 返回对象是否有效
    inline bool is_valid() const
    {
        return _env != NULL;
    }
    /// 不再管理MDB_env*的生命期
    MDB_env* detach()
    {
        MDB_env* pEnv = _env;
        _env = NULL;
        return pEnv;
    }
    /// 返回MDB_stat
    bool get_stat(MDB_stat& stat)
    {
        int err = mdb_env_stat(_env, &stat);
        return _log_err(err);
    }
    /// 返回env info
    bool get_info(MDB_envinfo& stat)
    {
        int err = mdb_env_info(_env, &stat);
        return _log_err(err);
    }
    /// 返回key size
    size_t get_keysize()
    {
        int err = mdb_env_get_maxkeysize(_env);
        return static_cast<size_t>(err);
    }
    /// 获取最大的读任务数
    size_t get_maxreaders()
    {
        uint readers = 0;
        int err = mdb_env_get_maxreaders(_env, &readers);
        return _log_err(err);
    }

    /// 关闭MDB_env*
    void close()
    {
        mdb_env_close(_env);
        _env = NULL;
    }
    /// 剔除引用,析构时调用
    void dispose()
    {
        // 只有自身持有该env时
        if(_env.ref_count() < 2 && is_valid())
        {
            close();
            return;
        }
        _env.reset() = NULL;
    }
};
/// lmdb 可读写的env对象
class lmdb_env : public lmdb_env_base
{
public:
    /// 默认的mdb_mode_t
    static const mdb_mode_t default_mdb_mode;
    /// 默认的env flags
    static const uint default_flags;
    /// 默认的env db数目
    static const uint default_dbs;
    /// 错误的mdb句柄
    static const MDB_dbi Mdb_NULL;

    /// 生成一个空的lmdb_env
    static lmdb_env create()
    {
        MDB_env* pEnv;
        int err = mdb_env_create(&pEnv);

        lmdb_env env;
        env._env = pEnv;
        env._log_err(err);
        return env;
    }
    /// 根据指定的mdb文件目录生成lmdb_env
    static lmdb_env create(const char* dir, size_t mapsize = 0, uint maxdb = 0,
        uint flags = default_flags, mdb_mode_t mode = default_mdb_mode)
    {
        lmdb_env env = create();
        if(!env.is_valid())
            return env;
        if(mapsize != 0)
        {
            env.set_mapsize(mapsize);
        }
        if(maxdb != 0)
        {
            env.set_maxdbs(maxdb);
        }
        // 打开失败时,关闭创建的句柄
        if(!env.open(dir, flags, mode))
        {
            env.close();
        }
        return env;
    }
    /// 从另外一个env复制参数创建一个新的env
    static lmdb_env create(lmdb_env_base& base_env, uint maxdb = 0)
    {
        const char* dir = base_env.get_dir().c_str();
        uint flags = base_env.get_flags();
        mdb_mode_t mode = base_env.get_mode();
        size_t mapsize = get_mapsize(base_env);
        flags &= ~MDB_RDONLY;
        return create(dir, mapsize, maxdb, flags, mode);
    }
    /// 获取env的map size
    static size_t get_mapsize(lmdb_env_base& env)
    {
        MDB_envinfo stat;
        if(!env.get_info(stat))
            return 0;
        return stat.me_mapsize;
    }
    /// 双倍扩容map size
    static bool double_map_size(lmdb_env& env)
    {
        size_t new_size = get_mapsize(env) * 2;
        return env.set_mapsize(new_size);
    }
public:
    /**
     * @brief 打开对应的mdb文件目录
     * @date 2018-06-06 09:00
     *
     * @param [in] dir 需要打开的文件夹
     * @param [in] flags 打开时的标志
     * @param [in] mode dir打开的模式(在Windows下无效)
     */
    bool open(const char* dir, uint flags = default_flags, 
        mdb_mode_t mode = default_mdb_mode)
    {
        // 文件夹不存在则自动进行创建
        bool isCreate = false;
        if(!FolderHelper::IsFolderExist(dir))
        {
            isCreate = FolderHelper::CreateFolder(dir, mode);
            if(!isCreate)
            {
                _log_err("create mdb directory failed.");
                return false;
            }
        }

        int err = mdb_env_open(_env, dir, flags, mode);
        if(!_log_err(err))
        {
            // 打开失败时,删除自动创建的文件夹
            FolderHelper::DeleteFolder(dir);
            return false;
        }
        if(_dir.c_str() != dir)
        {
            _dir = _strput(dir);
        }
        _flags = flags;
        _mode = mode;
        return true;
    }

    /// 设置flags
    bool set_flags(uint flags, bool isOff = false)
    {
        bool bOK = _log_err(mdb_env_set_flags(_env, flags, isOff ? 0 : 1));
        if(bOK) _flags = flags;
        return bOK;
    }
    /// 添加设置的标记位
    bool add_flags(uint flags)
    {
        return set_flags(_flags | flags);
    }
    /// 设置map size
    bool set_mapsize(size_t size)
    {
        int err = mdb_env_set_mapsize(_env, size);
        return _log_err(err);
    }
    /// 设置最大的读任务数
    bool set_maxreaders(uint readers)
    {
        int err = mdb_env_set_maxreaders(_env, readers);
        return _log_err(err);
    }
    /// 设置最大的db数
    bool set_maxdbs(uint dbs)
    {
        int err = mdb_env_set_maxdbs(_env, static_cast<MDB_dbi>(dbs));
        return _log_err(err);
    }
    /// 刷新数据到磁盘中
    bool flush(bool isForce)
    {
        int err = mdb_env_sync(_env, isForce ? 1 : 0);
        return _log_err(err);
    }
    /// 根据打开的参数重置env
    inline bool revert()
    {
        return open(_dir.c_str(), _flags, _mode);
    }

    /// 返回一个写事务
    lmdb_txn begin(uint flags = 0, MDB_txn* parent = NULL) const;
};
/// lmdb 只读的env对象
class lmdb_const_env : public lmdb_env_base
{
public:
    /// 根据指定的mdb文件目录生成lmdb_readonly_env
    static lmdb_const_env create(const char* path, size_t mapsize = 0, uint maxdb = 0,
        uint flags = lmdb_env::default_flags, mdb_mode_t mode = lmdb_env::default_mdb_mode)
    {
        // WRITE 和 RDONLY 不可共用
        flags &= ~MDB_WRITEMAP;
        flags |= MDB_RDONLY;

        return lmdb_env::create(path, mapsize, maxdb, flags, mode);
    }
public:
    lmdb_const_env() : lmdb_env_base() {}
    lmdb_const_env(const lmdb_env& env) : lmdb_env_base(env) {}
    /// 返回一个读事务
    lmdb_const_txn begin(uint flags = 0, MDB_txn* parent = NULL) const;
};
//--------------------------------------------------------- 
/// lmdb MDB_txn*的封装
template<class lmdb_env_type>
class lmdb_txn_base : public lmdb_base
{
public:
    typedef lmdb_env_type env_type;
protected:
    lmdb_env_type _env;
    uint _flags;
    MDB_txn* _parent;
    shared_obj<MDB_txn*> _txn;

    bool _begin(const lmdb_env_type& env, uint flags, MDB_txn* parent)
    {
        if(!env.is_valid())
        {
            if(_err_code == MDB_SUCCESS)
            {
                _log_err("begin:MDB_env* is null.");
            }
            return false;
        }
        MDB_txn* txn = NULL;
        int err = mdb_txn_begin(env, parent, flags, &txn);
        if(!_log_err(err))
            return false;

        _env = env;
        _txn = txn;
        _flags = flags;
        _parent = parent;
        return true;
    }
public:
    lmdb_txn_base()
    {
        _flags = 0;
        _parent = NULL;
        _txn = NULL;
    }
    virtual ~lmdb_txn_base()
    {
        dispose();
    }

    inline lmdb_env_type& get_env()
    {
        return _env;
    }
    inline const lmdb_env_type& get_env() const
    {
        return _env;
    }
    inline const shared_obj<MDB_txn*>& get_txn() const
    {
        return _txn;
    }
    inline operator MDB_txn*() const
    {
        return _txn;
    }
    inline bool is_valid() const
    {
        return _env.is_valid() && _txn != NULL;
    }
    /// 不再管理MDB_txn*的生命期
    MDB_txn* detach()
    {
        MDB_txn* pTxn = _txn;
        _txn = NULL;
        return pTxn;
    }

    /// 返回事务ID
    size_t get_id() const
    {
        return mdb_txn_id(_txn);
    }
    /// 放弃更改
    void abort()
    {
        mdb_txn_abort(_txn);
        _txn = NULL;
    }
    /// 剔除引用(析构时调用)
    void dispose()
    {
        if(_txn.ref_count() < 2 && is_valid())
        {
            abort();
            return;
        }
        _txn.reset() = NULL;
    }
    /// 根据上次的参数重新开始事务
    inline bool revert()
    {
        return _begin(_env, _flags, _parent);
    }
};
/// lmdb 读写事务
class lmdb_txn : public lmdb_txn_base<lmdb_env>
{
public:
    friend class lmdb_env;
public:
    /// 提交更改
    bool commit()
    {
        int err = mdb_txn_commit(_txn);
        _txn = NULL;
        return _log_err(err);
    }

    /// 返回打开的可 写数据库
    lmdb_dbi open(const char* name = NULL, uint flags = 0);
};
/// lmdb 只读事务
class lmdb_const_txn : public lmdb_txn_base<lmdb_const_env>
{
public:
    friend class lmdb_env;
    friend class lmdb_const_env;
public:
    lmdb_const_txn() : lmdb_txn_base() {}
    lmdb_const_txn(const lmdb_txn& txn) : lmdb_txn_base()
    {
        _env = txn.get_env();
        _txn = txn.get_txn();
    }

    lmdb_const_txn& reset()
    {
        mdb_txn_reset(_txn);
        return (*this);
    }
    lmdb_const_txn& renew()
    {
        int err = mdb_txn_renew(_txn);
        _log_err(err);
        return (*this);
    }

    /// 返回打开的只读数据库
    lmdb_const_dbi open(const char* name = NULL, uint flags = 0);
};
//--------------------------------------------------------- 
/// lmdb MDB_dbi*的封装
template<class lmdb_txn_type>
class lmdb_dbi_base : public lmdb_base
{
public:
    typedef lmdb_txn_type txn_type;
protected:
    bool _open(const lmdb_txn_type& txn, const char* name, uint flags)
    {
        if(!txn.is_valid())
        {
            if(_err_code == MDB_SUCCESS)
            {
                _log_err("open:MDB_txn* is null.");
            }
            return false;
        }
        MDB_dbi dbi = NULL;
        int err = mdb_dbi_open(txn, name, flags, &dbi);
        if(!_log_err(err))
            return false;

        _txn = txn;
        _flags = flags;
        _dbi = dbi;
        if(_name.c_str() != name)
        {
            _name = _strput(name);
        }
        return true;
    }
protected:
    lmdb_txn_type _txn;
    uint _flags;
    string _name;
    shared_obj<MDB_dbi> _dbi;
public:
    lmdb_dbi_base()
    {
        _flags = 0;
        _name = "";
        _dbi = lmdb_env::Mdb_NULL;
    }
    virtual ~lmdb_dbi_base()
    {
        dispose();
    }

    inline operator MDB_dbi() const
    {
        return _dbi;
    }
    inline lmdb_txn_type& get_txn()
    {
        return _txn;
    }
    inline const lmdb_txn_type& get_txn() const
    {
        return _txn;
    }
    inline const shared_obj<MDB_dbi>& get_dbi() const
    {
        return _dbi;
    }
    inline const string& get_name() const
    {
        return _name;
    }
    inline bool is_valid() const
    {
        return _txn.is_valid() && _dbi != lmdb_env::Mdb_NULL;
    }
    bool get_flags(uint& flags)
    {
        int err = mdb_dbi_flags(_txn, _dbi, &flags);
        return _log_err(err);
    }
    bool get_stat(MDB_stat& stat)
    {
        int err = mdb_stat(_txn, _dbi, &stat);
        return _log_err(err);
    }
    void close()
    {
        mdb_dbi_close(_txn.get_env(), _dbi);
        _dbi = lmdb_env::Mdb_NULL;
    }
    void dispose()
    {
        if(_dbi.ref_count() < 2 && is_valid())
        {
            close();
            return;
        }
        _dbi.reset() = lmdb_env::Mdb_NULL;
    }

    /// 获取指定键的值
    bool get(const MDB_val& key, MDB_val& data)
    {
        int err = mdb_get(_txn, _dbi, const_cast<MDB_val*>(&key), &data);
        return _log_err(err);
    }
    /// 根据上次打开的dbi参数重新打开
    inline bool revert()
    {
        const char* name = _name.length() < 1 ? NULL : _name.c_str();
        return _open(_txn, name, _flags);
    }
};
/// lmdb 可读写的db
class lmdb_dbi : public lmdb_dbi_base<lmdb_txn>
{
public:
    friend class lmdb_txn;
public:
    /// 清空db
    bool drop(bool isDel = false)
    {
        int err = mdb_drop(_txn, _dbi, isDel ? 1 : 0);
        return _log_err(err);
    }
    /// 设置键和值
    bool put(const MDB_val& key, const MDB_val& data, uint flags = 0)
    {
        int err = mdb_put(_txn, _dbi, const_cast<MDB_val*>(&key), const_cast<MDB_val*>(&data), flags);
        return _log_err(err);
    }
    /// 删除指定的键值
    bool del(const MDB_val& key, const MDB_val& data)
    {
        int err = mdb_del(_txn, _dbi, const_cast<MDB_val*>(&key), const_cast<MDB_val*>(&data));
        return _log_err(err);
    }
    /// 删除指定键下的所有值
    bool del(const MDB_val& key)
    {
        int err = mdb_del(_txn, _dbi, const_cast<MDB_val*>(&key), NULL);
        return _log_err(err);
    }

    lmdb_cursor cursor() const;
};
/// lmdb 只读的db
class lmdb_const_dbi : public lmdb_dbi_base<lmdb_const_txn>
{
public:
    friend class lmdb_const_txn;
public:
    lmdb_const_dbi() : lmdb_dbi_base<lmdb_const_txn>() {}
    lmdb_const_dbi(const lmdb_dbi& dbi) : lmdb_dbi_base<lmdb_const_txn>()
    {
        _dbi = dbi.get_dbi();
        _txn = dbi.get_txn();
    }

    lmdb_const_cursor cursor() const;
};
//--------------------------------------------------------- 
/// lmdb MDB_cursor*封装
template<class lmdb_dbi_type>
class lmdb_cursor_base : public lmdb_base
{
public:
    typedef lmdb_dbi_type dbi_type;
protected:
    lmdb_dbi_type _dbi;
    shared_obj<MDB_cursor*> _cursor;

    bool _cursor_open(const lmdb_dbi_type& dbi)
    {
        MDB_cursor* pCursor = NULL;
        int err = mdb_cursor_open(dbi.get_txn(), dbi, &pCursor);
        if(!_log_err(err))
            return false;
        _cursor = pCursor;
        return true;
    }
    bool _open(const lmdb_dbi_type& dbi)
    {
        if(!dbi.is_valid())
        {
            if(_err_code == MDB_SUCCESS)
            {
                _log_err("cursor:MDB_dbi is null.");
            }
            return false;
        }
        bool bOK = _cursor_open(dbi);
        if(bOK)
        {
            _dbi = dbi;
        }
        return bOK;
    }
public:
    lmdb_cursor_base()
    {
        _cursor = NULL;
    }
    virtual ~lmdb_cursor_base()
    {
        dispose();
    }

    inline lmdb_dbi_type& get_dbi()
    {
        return _dbi;
    }
    inline const lmdb_dbi_type& get_dbi() const
    {
        return _dbi;
    }
    inline const shared_obj<MDB_cursor*>& get_cursor() const
    {
        return _cursor;
    }
    inline operator MDB_cursor*() const
    {
        return _cursor;
    }
    inline bool is_valid() const
    {
        return _dbi.is_valid() && _cursor != NULL;
    }
    void close()
    {
        mdb_cursor_close(_cursor);
        _cursor = NULL;
    }
    void dispose()
    {
        if(_cursor.ref_count() < 2 && is_valid())
        {
            close();
            return;
        }
        _cursor.reset() = NULL;
    }

    size_t count()
    {
        size_t countp = 0;
        int err = mdb_cursor_count(_cursor, &countp);
        if(!_log_err(err))
            return 0;
        return countp;
    }
    bool get(MDB_val& key, MDB_val& data, MDB_cursor_op op)
    {
        int err = mdb_cursor_get(_cursor, &key, &data, op);
        return _log_err(err);
    }
    inline bool revert()
    {
        return _cursor_open(_dbi);
    }
};
/// lmdb 可读写的游标
class lmdb_cursor : public lmdb_cursor_base<lmdb_dbi>
{
public:
    friend class lmdb_dbi;
public:
    /// 添加键和值
    bool put(const MDB_val& key, const MDB_val& data, uint flags)
    {
        int err = mdb_cursor_put(_cursor, const_cast<MDB_val*>(&key), const_cast<MDB_val*>(&data), flags);
        return _log_err(err);
    }
    /// 删除游标当前键值
    bool del(uint flags)
    {
        int err = mdb_cursor_del(_cursor, flags);
        return _log_err(err);
    }
};
/// lmdb 只读的游标
class lmdb_const_cursor : public lmdb_cursor_base<lmdb_const_dbi>
{
public:
    friend class lmdb_const_dbi;
public:
    lmdb_const_cursor() : lmdb_cursor_base() {}
    lmdb_const_cursor(const lmdb_cursor& cursor) : lmdb_cursor_base()
    {
        _dbi = cursor.get_dbi();
        _cursor = cursor.get_cursor();
    }

    /// 重置一个只读的游标
    bool renew()
    {
        int err = mdb_cursor_renew(_dbi.get_txn(), _cursor);
        return _log_err(err);
    }
};
//--------------------------------------------------------- 
/// lmdb lmdb_cursor接口封装
template<class lmdb_cursor_type, class key_converter, class value_converter>
class lmdb_cursor_iterator_base
{
public:
    typedef lmdb_cursor_type cursor_type;
    typedef typename cursor_type::dbi_type dbi_type;
    typedef typename dbi_type::txn_type txn_type;
    typedef typename txn_type::env_type env_type;

    typedef key_converter key_converter;
    typedef value_converter value_converter;
    typedef typename key_converter::value_type key_type;
    typedef typename value_converter::value_type value_type;
protected:
    lmdb_cursor_type _cursor;

    dbi_type& _dbi()
    {
        return _cursor.get_dbi();
    }
    txn_type& _txn()
    {
        return _dbi().get_txn();
    }
    env_type& _env()
    {
        return _txn().get_env();
    }

    inline bool _get(MDB_cursor_op op)
    {
        MDB_val mdbK;
        MDB_val mdbV;
        bool bOK = _cursor.get(mdbK, mdbV, op);
        if(bOK)
        {
            key_converter kcvt;
            value_converter vcvt;
            kcvt.From(mdbK, Key);
            vcvt.From(mdbV, Value);
        }
        return bOK;
    }
    const lmdb_base& _get_error() const
    {
        int err = _cursor.error();
        if(err != MDB_SUCCESS)
            return _cursor;
        err = _cursor.get_dbi().error();
        if(err != MDB_SUCCESS)
            return _cursor.get_dbi();
        err = _cursor.get_dbi().get_txn().error();
        if(err != MDB_SUCCESS)
            return _cursor.get_dbi().get_txn();
        return _cursor.get_dbi().get_txn().get_env();
    }
public:
    lmdb_cursor_iterator_base() {}
    lmdb_cursor_iterator_base(const lmdb_cursor_type& cursor) : _cursor(cursor) {}

    key_type Key;
    value_type Value;

    inline bool is_valid() const
    {
        return _cursor.is_valid();
    }

    inline bool first()
    {
        return _get(MDB_FIRST);
    }
    inline bool current()
    {
        return _get(MDB_GET_CURRENT);
    }
    inline bool last()
    {
        return _get(MDB_LAST);
    }
    inline bool next()
    {
        return _get(MDB_NEXT);
    }
    inline bool prev()
    {
        return _get(MDB_PREV);
    }

    /// 获取指定键的值,并将键和值存到itr中
    inline bool get(const key_type& key)
    {
        MDB_val mdbK;
        MDB_val mdbV;
        key_converter kcvt;
        kcvt.To(key, mdbK);
        bool bOK = _cursor.get_dbi().get(mdbK, mdbV);
        if(bOK)
        {
            Key = key;
            value_converter vcvt;
            vcvt.From(mdbV, Value);
        }
        return bOK;
    }
    /// 获取指定键的值
    inline bool get(const key_type& key, value_type& val)
    {
        MDB_val mdbK;
        MDB_val mdbV;
        key_converter kcvt;
        kcvt.To(key, mdbK);
        bool bOK = _cursor.get_dbi().get(mdbK, mdbV);
        if(bOK)
        {
            value_converter vcvt;
            vcvt.From(mdbV, val);
        }
        return bOK;
    }
    /// 重置iterator为初始状态
    bool revert()
    {
        if(_cursor.is_valid())
            _cursor.close();
        if(_dbi().is_valid())
            _dbi().close();
        if(_txn().is_valid())
            _txn().abort();
        return _txn().revert() && _dbi().revert() && _cursor.revert();
    }
    /// 当前key数目
    inline size_t count()
    {
        return _cursor.count();
    }

    inline int error() const
    {
        return _get_error().error();
    }
    inline const string& error_msg() const
    {
        return _get_error().error_msg();
    }

    inline lmdb_cursor_type& operator *()
    {
        return _cursor;
    }
    inline lmdb_cursor_type* operator ->()
    {
        return &(operator *());
    }
    inline const lmdb_cursor_type& operator *() const
    {
        return _cursor;
    }
    inline const lmdb_cursor_type* operator ->() const
    {
        return &(operator *());
    }
};
/// lmdb可读写的游标迭代器
template<class key_converter, class value_converter>
class lmdb_cursor_iterator : public lmdb_cursor_iterator_base<lmdb_cursor, key_converter, value_converter>
{
public:
    lmdb_cursor_iterator() : lmdb_cursor_iterator_base<lmdb_cursor, key_converter, value_converter>() {}
    lmdb_cursor_iterator(const lmdb_cursor& cur) : lmdb_cursor_iterator_base<lmdb_cursor, key_converter, value_converter>(cur) {}

    /// 添加键和值
    inline bool put(const key_type& key, const value_type& val, uint flags = 0)
    {
        MDB_val mdbK;
        MDB_val mdbV;
        key_converter kcvt;
        value_converter vcvt;
        kcvt.To(key, mdbK);
        vcvt.To(val, mdbV);
        return _cursor.put(mdbK, mdbV, flags);
    }
    /// 单次修改并提交(自动尝试因MDB_MAP_FULL导致失败的情况)
    bool put_commit(const key_type& key, const value_type& data, uint flags = 0)
    {
        if(put(key, data, flags) && commit())
            return true;
        if(error() != MDB_MAP_FULL)
            return false;
        if(double_map_size() && revert())
            return put_commit(key, data, flags);
        return false;
    }
    /// 删除游标当前的键和值
    inline bool del(uint flags = 0)
    {
        return _cursor.del(flags);
    }

    /// 设置游标当前值
    inline bool set(const value_type& data)
    {
        return put(Key, data, MDB_CURRENT);
    }
    /// 设置游标当前键值
    inline bool set(const key_type& key, const value_type& val)
    {
        return put(key, val, MDB_CURRENT);
    }

    /// 删除指定的键下的所有值
    bool erase(const key_type& key)
    {
        MDB_val mdbK;
        key_converter kcvt;
        kcvt.To(key, mdbK);
        return _dbi().del(mdbK);
    }
    /// 删除指定的键和值
    bool erase(const key_type& key, const value_type& val)
    {
        MDB_val mdbK;
        MDB_val mdbV;
        key_converter kcvt;
        value_converter vcvt;
        kcvt.To(key, mdbK);
        vcvt.To(val, mdbV);
        return _dbi().del(mdbK, mdbV);
    }

    /// 清空数据库
    bool drop(bool isDel = false)
    {
        return _dbi().drop(isDel);
    }
    /// 取消事务
    void abort()
    {
        _txn().abort();
    }
    /// 提交更改
    bool commit()
    {
        return _txn().commit();
    }
    /// 刷新数据到disk
    bool flush(bool isForce = false)
    {
        return _env().flush(isForce);
    }
    /**
     * @brief 对env map_size进行扩容
     * @warning 仅在put或者commit返回错误码MDB_MAP_FULL时需要调用处理
     * @date 2018-06-13 15:30
     */
    bool double_map_size()
    {
        lmdb_txn& txn = _txn();
        if(txn.is_valid())
        {
            txn.abort();
        }
        _dbi().close();
        return lmdb_env::double_map_size(_env());
    }
};
/// lmdb只读的游标迭代器
template<class key_converter, class value_converter>
class lmdb_cursor_const_iterator : public lmdb_cursor_iterator_base<lmdb_const_cursor, key_converter, value_converter>
{
public:
    lmdb_cursor_const_iterator() : lmdb_cursor_iterator_base<lmdb_const_cursor, key_converter, value_converter>() {}
    lmdb_cursor_const_iterator(const lmdb_cursor& cur) : lmdb_cursor_iterator_base<lmdb_const_cursor, key_converter, value_converter>(cur) {}
    lmdb_cursor_const_iterator(const lmdb_const_cursor& cur) : lmdb_cursor_iterator_base<lmdb_const_cursor, key_converter, value_converter>(cur) {}
    lmdb_cursor_const_iterator(const lmdb_cursor_iterator<key_converter, value_converter>& itr) : lmdb_cursor_iterator_base<lmdb_const_cursor, key_converter, value_converter>(*itr) {}

    /// 重置只读游标
    inline bool renew()
    {
        return _cursor.renew();
    }
};
//--------------------------------------------------------- 
/**
 * @brief 空的MDB_val转换器
 * @date 2018-07-19 22:56:29
 */
class lmdb_null_converter
{
public:
    typedef MDB_val value_type;
    inline void From(const MDB_val& mdbV, value_type& data) { data = mdbV; }
    inline void To(const value_type& data, MDB_val& mdbV) { mdbV = data; }
};
/**
 * @brief lmdb ByteArray数据转换模板
 * @date 2018-07-19 21:46:02
 */
class lmdb_bytearray_converter
{
public:
    typedef ByteArray value_type;

    void From(const MDB_val& mdbV, value_type& data)
    {
        data = ByteArray(reinterpret_cast<byte*>(mdbV.mv_data), mdbV.mv_size);
    }
    void To(const value_type& data, MDB_val& mdbV)
    {
        mdbV.mv_data = const_cast<byte*>(data.GetBuffer());
        mdbV.mv_size = data.GetLength();
    }
};
/**
 * @brief lmdb POD类型数据转换模板(uint,int,double)
 * @date 2018-07-19 22:05:21
 */
template<class T>
class lmdb_pod_converter
{
protected:
    ByteBuilder _buff;
public:
    typedef T value_type;

    void From(const MDB_val& mdbV, value_type& data)
    {
        ByteArray val(reinterpret_cast<byte*>(mdbV.mv_data), mdbV.mv_size);
        ByteConvert::ToObject<value_type>(val, data);
    }
    void To(const value_type& data, MDB_val& mdbV)
    {
        _buff.Clear();

        ByteConvert::FromObject<value_type>(data, _buff);
        mdbV.mv_data = reinterpret_cast<void*>(const_cast<byte*>(_buff.GetBuffer()));
        mdbV.mv_size = _buff.GetLength();
    }
};
/**
 * @brief lmdb string数据转换模板
 * @date 2018-07-19 22:05:54
 */
class lmdb_string_converter
{
public:
    typedef string value_type;

    void From(const MDB_val& mdbV, value_type& data)
    {
        char* p = reinterpret_cast<char*>(const_cast<void*>(mdbV.mv_data));
        data.append(p, mdbV.mv_size);
    }
    void To(const value_type& data, MDB_val& mdbV)
    {
        mdbV.mv_data = const_cast<char*>(data.c_str());
        mdbV.mv_size = data.length();
    }
};
//--------------------------------------------------------- 
/* Key和Value基于字节ByteArray的iteartor */
typedef lmdb_cursor_iterator<lmdb_bytearray_converter, lmdb_bytearray_converter> lmdb_iterator;
typedef lmdb_cursor_const_iterator<lmdb_bytearray_converter, lmdb_bytearray_converter> lmdb_const_iterator;
/* Key和Value基于string的iterator */
typedef lmdb_cursor_iterator<lmdb_string_converter, lmdb_string_converter> lmdb_string_iterator;
typedef lmdb_cursor_const_iterator<lmdb_string_converter, lmdb_string_converter> lmdb_string_const_iterator;
//--------------------------------------------------------- 
/**
 * @brief 用于lmdb操作常用的辅助接口
 * @date 2018-10-29 22:31:47
 */
class lmdb_helper
{
protected:
    lmdb_helper() {}
public:
    static lmdb_env open(const char* dir)
    {
        // 以无锁共享的方式打开,由agent控制互斥
        return lmdb_env::create(dir, 0, 0, MDB_NOLOCK);
    }
    static lmdb_cursor open(lmdb_env& env)
    {
        return env.begin().open().cursor();
    }
    static lmdb_cursor open_cursor(const char* dir)
    {
        lmdb_env env = open(dir);
        return open(env);
    }
    static lmdb_const_env open_readonly(const char* dir)
    {
        return lmdb_const_env::create(dir);
    }
    static lmdb_const_cursor open_readonly(lmdb_env& env)
    {
        return env.begin().open().cursor();
    }
    static lmdb_const_cursor open_readonly(lmdb_const_env& env)
    {
        return env.begin().open().cursor();
    }
    static lmdb_const_cursor open_readonly_cursor(const char* dir)
    {
        lmdb_const_env env = open_readonly(dir);
        return open_readonly(env);
    }
};
//--------------------------------------------------------- 
} // namespace lmdb_extractor 
} // namespace wrapper
} // namespace zhou_yb 
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_LMDB_EXTRACTOR_H_
//========================================================= 